{
 "cells": [
  {
   "cell_type": "raw",
   "metadata": {
    "vscode": {
     "languageId": "raw"
    }
   },
   "source": [
    "---\n",
    "title: Value semantics\n",
    "sidebar_position: 2\n",
    "description: An explanation of Mojo's value-semantic defaults.\n",
    "---"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Mojo doesn't enforce value semantics or reference semantics. It supports them\n",
    "both and allows each type to define how it is created, copied, and moved (if at\n",
    "all). So, if you're building your own type, you can implement it to support\n",
    "value semantics, reference semantics, or a bit of both. That said, Mojo is\n",
    "designed with argument behaviors that default to value semantics, and it\n",
    "provides tight controls for reference semantics that avoid memory errors.\n",
    "\n",
    "The controls over reference semantics are provided by the [value ownership\n",
    "model](/mojo/manual/values/ownership), but before we get into the syntax\n",
    "and rules for that, it's important that you understand the principles of value\n",
    "semantics. Generally, it means that each variable has unique access to a value,\n",
    "and any code outside the scope of that variable cannot modify its value."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Intro to value semantics"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "In the most basic situation, sharing a value-semantic type means that you create\n",
    "a copy of the value. This is also known as \"pass by value.\" For example,\n",
    "consider this code:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "1\n",
      "2\n"
     ]
    }
   ],
   "source": [
    "x = 1\n",
    "y = x\n",
    "y += 1\n",
    "\n",
    "print(x)\n",
    "print(y)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "We assigned the value of `x` to `y`, which creates the value for `y` by making a\n",
    "copy of `x`. When we increment `y`, the value of `x` doesn't change. Each\n",
    "variable has exclusive ownership of a value.\n",
    "\n",
    "Whereas, if a type instead uses reference semantics, then `y` would point to\n",
    "the same value as `x`, and incrementing either one would affect the value for\n",
    "both. Neither `x` nor `y` would \"own\" the value, and any variable would be\n",
    "allowed to reference it and mutate it.\n",
    "\n",
    "Numeric values in Mojo are value semantic because they're trivial types, which\n",
    "are cheap to copy. \n",
    "\n",
    "Here's another example with a function:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "2\n",
      "1\n"
     ]
    }
   ],
   "source": [
    "def add_one(y: Int):\n",
    "    y += 1\n",
    "    print(y)\n",
    "\n",
    "x = 1\n",
    "add_one(x)\n",
    "print(x)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Again, the `y` value is a copy and the function cannot modify the original `x`\n",
    "value.\n",
    "\n",
    "If you're familiar with Python, this is probably familiar so far, because the\n",
    "code above behaves the same in Python. However, Python is not value semantic.\n",
    "\n",
    "It gets complicated, but let's consider a situation in which you call a Python\n",
    "function and pass an object with a pointer to a heap-allocated value. Python\n",
    "actually gives that function a reference to your object, which allows the\n",
    "function to mutate the heap-allocated value. This can cause nasty bugs if\n",
    "you're not careful, because the function might incorrectly assume it has unique\n",
    "ownership of that object.\n",
    "\n",
    "In Mojo, the default behavior for all function arguments is to use value\n",
    "semantics. If the function wants to modify the value of an incoming argument,\n",
    "then it must explicitly declare so, which avoids accidental mutations of the\n",
    "original value.\n",
    "\n",
    "All Mojo types passed to a `def` function can be treated as mutable,\n",
    "which maintains the expected mutability behavior from Python. But by default, it\n",
    "is mutating a uniquely-owned value, not the original value.\n",
    "\n",
    "For example, when you pass an instance of a `SIMD` vector to a `def`\n",
    "function it creates a unique copy of all values. Thus, if we modify the\n",
    "argument in the function, the original value is unchanged:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[9, 2, 3, 4]\n",
      "[1, 2, 3, 4]\n"
     ]
    }
   ],
   "source": [
    "def update_simd(t: SIMD[DType.int32, 4]):\n",
    "    t[0] = 9\n",
    "    print(t)\n",
    "\n",
    "v = SIMD[DType.int32, 4](1, 2, 3, 4)\n",
    "update_simd(v)\n",
    "print(v)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "If this were Python code, the function would modify the original object, because\n",
    "Python shares a reference to the original object.\n",
    "\n",
    "However, not all types are inexpensive to copy. Copying a `String` or `List`\n",
    "requires allocating heap memory, so we want to avoid copying one by accident.\n",
    "When designing a type like this, ideally you want to prevent _implicit_ copies,\n",
    "and only make a copy when it's explicitly requested. "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Value semantics in `def` vs `fn`"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The arguments above are mutable because a [`def`\n",
    "function](/mojo/manual/functions#def-functions) has special treatment for\n",
    "the default\n",
    "[`borrowed` argument convention](/mojo/manual/values/ownership#argument-conventions).\n",
    "\n",
    "Whereas, `fn` functions always receive `borrowed` arguments as immutable\n",
    "references. This is a memory optimization to avoid making\n",
    "unnecessary copies.\n",
    "\n",
    "For example, let's create another function with the `fn` declaration. In this\n",
    "case, the `y` argument is immutable by default, so if the function wants to\n",
    "modify the value in the local scope, it needs to make a local copy:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "3\n",
      "1\n"
     ]
    }
   ],
   "source": [
    "fn add_two(y: Int):\n",
    "    # y += 2 # This will cause a compiler error because `y` is immutable\n",
    "    # We can instead make an explicit copy:\n",
    "    var z = y\n",
    "    z += 2\n",
    "    print(z)\n",
    "\n",
    "x = 1\n",
    "add_two(x)\n",
    "print(x)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "This is all consistent with value semantics because each variable maintains\n",
    "unique ownership of its value.\n",
    "\n",
    "The way the `fn` function receives the `y` value is a \"look but don't touch\"\n",
    "approach to value semantics. This is also a more memory-efficient approach when\n",
    "dealing with memory-intensive arguments, because Mojo doesn't make any copies\n",
    "unless we explicitly make the copies ourselves.\n",
    "\n",
    "Thus, the default behavior for `def` and `fn` arguments is fully value\n",
    "semantic: arguments are either copies or immutable references, and any living\n",
    "variable from the callee is not affected by the function.\n",
    "\n",
    "But we must also allow reference semantics (mutable references) because it's\n",
    "how we build performant and memory-efficient programs (making copies of\n",
    "everything gets really expensive). The challenge is to introduce reference\n",
    "semantics in a way that does not disturb the predictability and safety of value\n",
    "semantics.\n",
    "\n",
    "The way we do that in Mojo is, instead of enforcing that every variable have\n",
    "\"exclusive access\" to a value, we ensure that every value has an \"exclusive\n",
    "owner,\" and destroy each value when the lifetime of its owner ends. \n",
    "\n",
    "On the next page about [value\n",
    "ownership](/mojo/manual/values/ownership), you'll learn how to modify\n",
    "the default argument conventions, and safely use reference semantics so every\n",
    "value has only one owner at a time."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Python-style reference semantics"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    ":::note\n",
    "\n",
    "If you will always use strict type declarations, you\n",
    "can skip this section because it only applies to Mojo code using `def`\n",
    "functions without type declarations (or values declared as\n",
    "[`object`](/mojo/stdlib/builtin/object/object)).\n",
    "\n",
    ":::\n",
    "\n",
    "As we said at the top of this page, Mojo doesn't enforce value semantics or\n",
    "reference semantics. It's up to each type author to decide how an instance of\n",
    "their type should be created, copied, and moved (see [Value\n",
    "lifecycle](/mojo/manual/lifecycle/)). Thus, in order to provide compatibility\n",
    "with Python, Mojo's `object` type is designed to support Python's style of\n",
    "argument passing for functions, which is different from the other types in\n",
    "Mojo.\n",
    "\n",
    "Python's argument-passing convention is called \"pass by object reference.\" This\n",
    "means when you pass a variable to a Python function, you actually pass a\n",
    "reference to the object, as a value (so it's not strictly reference semantics).\n",
    "\n",
    "Passing the object reference \"as a value\" means that the argument name is just\n",
    "a container that acts like an alias to the original object. If you reassign the\n",
    "argument inside the function, it does not affect the caller's original value.\n",
    "However, if you modify the object itself (such as call `append()` on a list),\n",
    "the change is visible to the original object outside the function.\n",
    "\n",
    "For example, here's a Python function that receives a list and modifies it:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "func: [1, 2, 3]\n",
      "orig: [1, 2, 3]\n"
     ]
    }
   ],
   "source": [
    "%%python\n",
    "def modify_list(l):\n",
    "    l.append(3)\n",
    "    print(\"func:\", l)\n",
    "\n",
    "ar = [1, 2]\n",
    "modify_list(ar)\n",
    "print(\"orig:\", ar)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "In this example, it looks like the list is \"passed by reference\" because `l`\n",
    "modifies the original value.\n",
    "\n",
    "However, if the Python function instead _assigns_ a value to `l`, it does not\n",
    "affect the original value:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "func: [3, 4]\n",
      "orig: [1, 2]\n"
     ]
    }
   ],
   "source": [
    "%%python\n",
    "def change_list(l):\n",
    "    l = [3, 4]\n",
    "    print(\"func:\", l)\n",
    "\n",
    "ar = [1, 2]\n",
    "change_list(ar)\n",
    "print(\"orig:\", ar)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "This demonstrates how a Python argument holds the object reference _as a\n",
    "value_: the function can mutate the original value, but it can also assign a\n",
    "new object to the argument name."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Pass by object reference in Mojo"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Although we haven't finished implementing the\n",
    "[`object`](/mojo/stdlib/builtin/object/object) type to represent any Mojo\n",
    "type, our intention is to do so, and enable \"pass by object reference\" as\n",
    "described above for all dynamic types in a `def` function.\n",
    "\n",
    "That means you can have dynamic typing and \"pass by object reference\" behavior\n",
    "by simply writing your Mojo code like Python:\n",
    "\n",
    "1. Use `def` function declarations.\n",
    "2. Don't declare argument types.\n",
    "\n",
    ":::note TODO\n",
    "\n",
    "Mojo is not a complete superset of Python yet, and there is a lot to\n",
    "do in this department before Mojo supports all of Python's types and behaviors.\n",
    "As such, this is a topic that also still needs a lot of documentation.\n",
    "\n",
    ":::"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Mojo",
   "language": "mojo",
   "name": "mojo-jupyter-kernel"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "mojo"
   },
   "file_extension": ".mojo",
   "mimetype": "text/x-mojo",
   "name": "mojo"
  },
  "orig_nbformat": 4
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
